package edu.mit.media.fv.aqwidgets
{
	import edu.mit.media.fv.blocks.*;
	import edu.mit.media.fv.fluidspace.FluidSpace;
	
	import flash.display.Graphics;
	import flash.display.MovieClip;
	import flash.display.Sprite;
	import flash.events.MouseEvent;
	import flash.text.*;
	import flash.utils.Dictionary;
	
	public class AQMessageTimeline extends MovieClip
	{
		private var controller:FluidSpace;
		
		private const hcolor:uint = 0xF1F0A7;
		private const totalWidth:int = 525;
		private const totalHeight:int = 220;
		private const headerWidth:int = 100;
		private var cellWidth:int = 10;
		private const fontSize:int = 20;
		private var numMessages:int = 10;
		private const cellHeight:int = 50;
		
		//mapps the id of the src to the row index it is on
		private var srcRowIndexMapping:Dictionary = new Dictionary();
		private var glass:Sprite = new Sprite();
		public function AQMessageTimeline(controller:FluidSpace)
		{
			super();
			this.controller = controller;
			this.x = 100;
			this.y = 140;
			this.addChild(this.glass);
			
		}
		
		//messages is an array of objects with key id, src_id, reply_id, src_name, tags, text, msg_type
		//for example:{{id:45,src_id:12,src_name:"bob", reply_id:34, tags:"Business Letter",text:"", type:344},{}}
		public function setMessages(messages:Array):void{
			trace("Drawing Message Timeline");
			for(var j:int = 0 ; j<this.numChildren; j++){
				this.removeChildAt(j);
			}
			this.graphics.clear();
			numMessages = messages.length;
			srcRowIndexMapping = new Dictionary();
			cellWidth = (totalWidth-headerWidth)/numMessages;
			
			
			this.drawRows(messages);
			this.addChild(this.glass);
			this.drawMessageBlocks(messages);
			
		}
		
		public function drawRows(messages:Array):void{
			trace("AQmessageTimeline.drawRows(): "+numMessages+", "+messages);
			var maxIndex:int = 0;
			for(var i:int = 0; i<numMessages; i++){
				trace(messages[i]);
				var src_id:int = messages[i].src_id;
				var src_name:String = messages[i].src_name;
				var reply_id:int = messages[i].reply_id;
				var id:int = messages[i].id;
				var tags:String = messages[i].tags;
				var text:String = messages[i].text;
				var index:int = maxIndex;
				trace(src_id+src_name+id+tags+text+index+reply_id);
				if(srcRowIndexMapping[src_id] == null){
					index = maxIndex;
					var cellX:int = 0;
					var cellY:int =  int(index)*this.cellHeight;
					srcRowIndexMapping[src_id] = index;
					maxIndex = maxIndex+1;
					
					var srcLabel:AQTimeRow = new AQTimeRow(
						cellX,
						cellY+0.5*(this.cellHeight-fontSize),
						src_name);
					this.addChild(srcLabel);
				}
			}
			
			this.graphics.lineStyle(1,0xFFFFFF, 1, false, "normal", null, null, 3);
			for(var k:int = 0; k<this.numMessages; k++){
				
				this.graphics.moveTo(this.headerWidth+this.cellWidth*k, 0);
				AQMessageTimeline.dashLine(
					this.graphics,
					this.headerWidth+this.cellWidth*k,
					0,
					this.headerWidth+this.cellWidth*k,
					this.totalHeight,
					10,
					10);
			}
			this.graphics.lineStyle(1,0xFFFFFF);
		}
		
		private var childrenMap:Dictionary = new Dictionary();
		public function drawMessageBlocks(messages:Array):void{
			
			for(var i:int = 0; i<numMessages; i++){
				var src_id:int = messages[i].src_id;
				var src_name:String = messages[i].src_name;
				var reply_id:int = messages[i].reply_id;
				var id:int = messages[i].id;
				var tags:String = messages[i].tags;
				var text:String = messages[i].text;
				var type:Object = messages[i].msg_type;
				
				var index:int = srcRowIndexMapping[src_id];
				var cellX:int = 0;
				var cellY:int =  index*this.cellHeight;
				
				var model:Model = Model.getModel(id);
				if(model == null || !(model is MessageModel)){
					model = new MessageModel(id, type, this.controller);
				}
				var messageModel:MessageModel = MessageModel(model);
				messageModel.name = tags;
				messageModel.text = text;
				messageModel.authorID = src_id;
				messageModel.authorName = src_name;
				messageModel.replyID = reply_id;
				
				var block:Block = messageModel.getTimelineInstance();
				block.x = cellX+this.headerWidth+this.cellWidth*i;
				block.y = cellY;
				block.diameter = this.cellHeight;
				
				this.addChild(block);
				block.addEventListener(MouseEvent.CLICK, messageBlockSelected);
				
				if(reply_id != -1){
					if(this.childrenMap[reply_id] == null){
						this.childrenMap[reply_id] = [messageModel.id];
					}else{
						var children:Array = this.childrenMap[reply_id];
						children.push(messageModel.id);
					}
				}
				
			}
		}
		

		public function messageBlockSelected(event:MouseEvent):void{
			trace("Selecting Block");
			var block:Block = Block(event.currentTarget);
			this.glass.graphics.clear();
			
			var margin:int = 10;
			this.glass.graphics.beginFill(hcolor);
			this.glass.graphics.drawRoundRect(
				block.x-margin, block.y-margin,
				block.diameter+margin*2, block.diameter+margin*2,
				margin, margin);
			this.selectParent(block);
			this.selectChildren(block);
		}
		private function getBlock(id:int):Block{
			if(id == -1){
				return null;
			}
			var model:Model = Model.getModel(id);
			if(model == null){
				return null;
			}else{
				return model.getTimelineInstance();
			}
		}
		
		private function highlightBlock(b1:Block, b2:Block):void{
			var margin:int = 10;
			this.glass.graphics.beginFill(hcolor);
			this.glass.graphics.lineStyle();
			this.glass.graphics.drawRoundRect(
				b1.x-margin, b1.y-margin,
				b1.diameter+margin*2, b1.diameter+margin*2,
				margin, margin);
			this.glass.graphics.drawRoundRect(
				b2.x-margin, b2.y-margin,
				b2.diameter+margin*2, b2.diameter+margin*2,
				margin, margin);
			this.glass.graphics.lineStyle(margin, hcolor);
			this.glass.graphics.moveTo(b1.x+b1.radius,b1.y+b1.radius);
			this.glass.graphics.lineTo(b2.x+b2.radius,b2.y+b2.radius);
			this.graphics.endFill();
		}
		private function selectParent(block:Block):void{
			var model:MessageModel = MessageModel(block.model);
			var parent:Block = this.getBlock(model.replyID);
			if(parent != null){
				this.highlightBlock(parent, block);
				this.selectParent(parent);
			}
		}
		private function selectChildren(block:Block):void{
			var children:Array = this.childrenMap[block.model.id];
			if(children != null){
				for(var i:int = 0 ; i<children.length; i++){
					var childBlock:Block = this.getBlock(children[i]);
					if(childBlock != null){
						this.highlightBlock(block, childBlock);
						this.selectChildren(childBlock);
					}
					
				}
			}
		}
		
		public static function dashLine(g:Graphics,x1:Number,y1:Number,x2:Number,y2:Number,onLength:Number = 0,offLength:Number = 0):void {
			g.moveTo(x1,y1);
			if (offLength==0) {
			    g.lineTo(x2,y2);
			    return;
			}
			
			var dx:Number = x2-x1,
			    dy:Number = y2-y1,
			    lineLen:Number = Math.sqrt(dx*dx + dy*dy),
			    angle:Number = Math.atan2(dy, dx),
			    cosAngle:Number = Math.cos(angle),
			    sinAngle:Number = Math.sin(angle),
			    ondx:Number  = cosAngle*onLength,
			    ondy:Number  = sinAngle*onLength,
			    offdx:Number = cosAngle*offLength,
			    offdy:Number = sinAngle*offLength,
			
			    x:Number = x1,
			    y:Number = y1;
			
			
			var fullDashCountNumber:int = Math.floor(lineLen/(onLength+offLength));
			
			for (var i:int=0; i<fullDashCountNumber; i++){
			        g.lineTo(x+=ondx,y+=ondy);
			     g.moveTo(x+=offdx,y+=offdy);
			    }
			
			    var remainder:Number = lineLen - ((onLength+offLength)*fullDashCountNumber);
			
			    if (remainder>=onLength) {
			    g.lineTo(x+=ondx,y+=ondy);
			    } else {
			        g.lineTo(x2,y2);
			    }
			}
		
	}
}